/**
 * 
 */
package io.potato.ts.webservice.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import io.potato.core.util.Azdg;
import io.potato.core.util.IdWorker;
import io.potato.core.util.JaxbUtil;
import io.potato.core.util.Lists;
import io.potato.core.util.SmsUtil;
import io.potato.core.util.Strings;
import io.potato.ts.common.Constants;
import io.potato.ts.common.SmsIdWorker;
import io.potato.ts.domain.SmsSendingRecord;
import io.potato.ts.domain.SmsStatusReport;
import io.potato.ts.domain.SmsUpRecord;
import io.potato.ts.service.SmsAsyncService;
import io.potato.ts.service.SmsService;
import io.potato.ts.service.SmsStatusReportService;
import io.potato.ts.service.SmsUpRecordService;
import io.potato.ts.service.UserService;
import io.potato.ts.webservice.ErrorCode;
import io.potato.ts.webservice.SmsApiService;
import io.potato.ts.webservice.SmsApiServiceException;
import io.potato.ts.webservice.model.SmsMessage;
import io.potato.ts.webservice.model.SmsSendBody;
import io.potato.ts.webservice.model.response.DownSmsResponse;
import io.potato.ts.webservice.model.response.Response;
import io.potato.ts.webservice.model.response.SmsResult;
import io.potato.ts.webservice.model.response.SmsResultResponse;
import io.potato.ts.webservice.model.response.UpSmsResponse;
import io.potato.ts.webservice.model.response.UpSmsResponse.Sms;
import lombok.extern.slf4j.Slf4j;

/**
 * 短信对接接口服务实现类
 * @author timl
 * created: 2019年1月21日 上午9:55:39
 */
@Service
@Slf4j
public class SmsApiServiceImpl implements SmsApiService {
	
	@Autowired
	UserService userService;
	
	@Autowired
	SmsUpRecordService smsUp;
	
	@Autowired
	SmsStatusReportService statusReport;
	
	@Autowired
	SmsAsyncService smsAsync;
	
	@Autowired
	SmsService smsService;
	
	/**
	 * ID生成器
	 */
	@Autowired
	private SmsIdWorker idWorker;

	@Override
	public String checkUser(String username, String password) {
		try {
			// 验证用户是否合法
			this.checkUserPassword(username, password);
			
			//  生成返回结果
			return this.toXml(new Response());
		} catch (SmsApiServiceException e) {
			log.error(e.getMessage());
			return this.toXml(new Response(e.getCode(), e.getMessage()));
		} catch (Exception e) {
			log.error("", e);
			return this.toXml(new Response(ErrorCode.SERVER_ERROR, "server error"));
		}
	}

	@Override
	public String getUpSms(String username, String password, String destaddr) {
		try {
			
			destaddr = Strings.trimToEmpty(destaddr);
			
			// 验证用户是否合法
			String userCode = this.checkUserPassword(username, password);
			
			// 查询未读的上行短信
			List<SmsUpRecord> list = smsUp.getUnReadUpSms(userCode + destaddr);
			
			if (list.size() > 0) {
				// 异步更新查询次数
				this.smsUp.updateReadTimesAsync(list);
				
				// 生成指定格式的返回结果
				List<Sms> smsList = new ArrayList<>();
				list.forEach(s -> smsList.add(new Sms(
						s.getFromNum(), 
						s.getDestNum(), 
						s.getContent(), 
						s.getMsgId(), 
						s.getReceiveTime())));
				return this.toXml(new UpSmsResponse(smsList));
				
			} else {
				return this.toXml(new Response());
			}

		} catch (SmsApiServiceException e) {
			log.error(e.getMessage());
			return this.toXml(new Response(e.getCode(), e.getMessage()));
		} catch (Exception e) {
			log.error("", e);
			return this.toXml(new Response(ErrorCode.SERVER_ERROR, "server error"));
		}
	}

	@Override
	public String rspUpSms(String username, String password, String msgid) {
		try {
			
			if (StringUtils.isEmpty(msgid)) {
				throw new SmsApiServiceException(ErrorCode.PARAM_INVALID, "参数错误");
			}
			
			// 验证用户是否合法
			this.checkUserPassword(username, password);
			
			List<String> msgidList = Lists.toList(msgid);
			
			// 异步更新已读状态
			this.smsUp.updateReadStatusAsync(msgidList);
			
			return this.toXml(new Response());
		} catch (SmsApiServiceException e) {
			log.error(e.getMessage());
			return this.toXml(new Response(e.getCode(), e.getMessage()));
		} catch (Exception e) {
			log.error("", e);
			return this.toXml(new Response(ErrorCode.SERVER_ERROR, "server error"));
		}
	}

	@Override
	public String insertDownSms(String username, String password, String batch, String sendbody) {
		try {
			
			// 验证用户是否合法
			String userCode = this.checkUserPassword(username, password);
			
			if (StringUtils.isEmpty(sendbody)) {
				throw new SmsApiServiceException(ErrorCode.PARAM_INVALID, "参数错误");
			}
			
			// 解析sendbody参数， xml格式
			SmsSendBody sendBody = JaxbUtil.xmlToBean(sendbody, SmsSendBody.class);
			
			// 检查参数格式
			this.checkSendBody(sendBody);
			
			// 发送短信
			List<SmsSendingRecord> result = this.submitSms(userCode, batch, sendBody);
			
			// 生成结果
			List<String> msgIdList = new ArrayList<>();
			result.forEach(s -> {
				msgIdList.add(s.getDestNum() + "," + s.getMsgId());
			});
			
			return this.toXml(new DownSmsResponse(msgIdList));
		} catch (SmsApiServiceException e) {
			log.error(e.getMessage());
			return this.toXml(new Response(e.getCode(), e.getMessage()));
		} catch (Exception e) {
			log.error("", e);
			return this.toXml(new Response(ErrorCode.SERVER_ERROR, "server error"));
		}
	}
	/**
	 * 检查并处理参数

	 * @param sendBody
	 * @throws SmsApiServiceException
	 */
	private void checkSendBody(SmsSendBody sendBody) throws SmsApiServiceException {
		if (sendBody == null) {
			throw new SmsApiServiceException(ErrorCode.PARAM_INVALID, "参数错误[semdBody]");
		}
		
		if (sendBody.getMessage() == null || sendBody.getMessage().isEmpty()) {
			throw new SmsApiServiceException(ErrorCode.PARAM_INVALID, "参数错误[Message]");
		}
		
		// boolean noPublicContent = StringUtils.isEmpty(sendBody.getPublicContent());
		
		/*for (SmsMessage smsMsg : sendBody.getMessage()) {
			if (noPublicContent && StringUtils.isEmpty(smsMsg.getContent())) {
				throw new SmsApiServiceException(ErrorCode.PARAM_INVALID, "参数错误[content]");
			}
		}*/
	}
	
	/**
	 * 提交要发送的短信
	 * @param userCode
	 * @param batch
	 * @param sendBody
	 * @return
	 */
	private List<SmsSendingRecord> submitSms(String userCode, String batch, SmsSendBody sendBody) {

		List<SmsMessage> smsMsgList = sendBody.getMessage();
		
		// 短信发送记录列表
		List<SmsSendingRecord> sendingList = new ArrayList<>();
		
		batch = Strings.trimToEmpty(batch);
		LocalDateTime now = LocalDateTime.now();
		String lot = Strings.uuid();
		String batchCode = userCode + batch;
		int seq = NumberUtils.toInt(userCode) % Constants.SEND_WORKER_NUM;
		String publicContent = getContent(sendBody.getPublicContent());
		
		// 根据传过来的参数生成一条条短信发送记录
		for (SmsMessage s : smsMsgList) {
			if (StringUtils.isEmpty(s.getMobile())) {
				// 忽略没有号码的
				continue;
			}
			
			// 短信内容
			String content = getContent(s.getContent()) + publicContent;
			
			if (StringUtils.isEmpty(content)) {
				// 忽略没有短信内容的
				continue;
			}
			
			// 实际发送的拓展码
			String extendCode = batchCode + Strings.trimToEmpty(s.getOrgaddr());
			
			if (extendCode.length() > 7) {
				// 扩展码超长
				continue;
			}
			
			// 号码可以是逗号分隔多个
			String[] mobileArr = s.getMobile().split(",");
			
			for (String mobile : mobileArr) {
				if (!SmsUtil.isPhoneNumber(mobile)) {
					// 不合法的号码都忽略掉
					continue;
				}
				
				SmsSendingRecord sendingRec = new SmsSendingRecord();
				sendingRec.setUserCode(userCode);
				sendingRec.setBatchCode(batchCode);
				sendingRec.setExtendCode(extendCode);
				sendingRec.setSenderType(Constants.SENDER_TYPE_API);
				sendingRec.setSendTime(s.getSendtime() == null ? now : s.getSendtime());
				sendingRec.setContent(content);
				sendingRec.setDestNum(mobile);
				sendingRec.setLot(lot);
				sendingRec.setStatus(Constants.SendingStatus.TO_BE_SEND);
				sendingRec.setSeq(seq);
				sendingRec.setTryTimes(0);
				sendingRec.setSmsType(Constants.SmsType.NORMAL);
				sendingRec.setMsgId("" + idWorker.nextId());
				sendingRec.setNeedReport(s.getNeedreport());
				
				sendingList.add(sendingRec);
			}
		}
		
		this.smsService.submitBatchSms(userCode, sendingList);
		
		return sendingList;
	}

	private static final String CDATA_START = "<![CDATA[";
	private static final String CDATA_END = "]]>";

	private String getContent(String s) {
		String c = StringUtils.trimToEmpty(s);
		if (c.startsWith(CDATA_START) && c.endsWith(CDATA_END)) {
			c = c.substring(CDATA_START.length());
			c = c.substring(0, c.length() - CDATA_END.length());
		}
		return c;
	}
	
	@Override
	public String getDownSmsResult(String username, String password, String batch, String cnt) {
		try {
			
			// 验证用户是否合法
			String userCode = this.checkUserPassword(username, password);
			
			String batchCode = userCode + Strings.trimToEmpty(batch);
			
			// 根据拓展码查询
			List<SmsStatusReport> list = this.statusReport.getStatusReport(batchCode, NumberUtils.toInt(cnt, 10));
			
			// 同步更新已读状态
			this.statusReport.updateReadStatus(list);
			
			return statusReportResult(list);
		} catch (SmsApiServiceException e) {
			log.error(e.getMessage());
			return this.toXml(new Response(e.getCode(), e.getMessage()));
		} catch (Exception e) {
			log.error("", e);
			return this.toXml(new Response(ErrorCode.SERVER_ERROR, "server error"));
		}
	}

	@Override
	public String getSpecialDownSmsResult(String username, String password, String batch, String msgid) {
		try {
			
			if (StringUtils.isEmpty(msgid)) {
				throw new SmsApiServiceException(ErrorCode.PARAM_INVALID, "参数错误");
			}
			
			// 验证用户是否合法
			String userCode = this.checkUserPassword(username, password);
			
			String batchCode = userCode + Strings.trimToEmpty(batch);
			
			List<String> msgIdList = Lists.toList(msgid);
			
			// 根据短信唯一ID查询
			List<SmsStatusReport> list = this.statusReport.getStatusReport(batchCode, msgIdList);
			
			// 异步更新已读状态
			this.statusReport.updateReadStatusAsync(list);
			
			return statusReportResult(list);
		} catch (SmsApiServiceException e) {
			log.error(e.getMessage());
			return this.toXml(new Response(e.getCode(), e.getMessage()));
		} catch (Exception e) {
			log.error("", e);
			return this.toXml(new Response(ErrorCode.SERVER_ERROR, "server error"));
		}
	}

	private String statusReportResult(List<SmsStatusReport> list) {
		if (list.size() > 0) {
			
			List<SmsResult> resultList = new ArrayList<>();
			list.forEach(s -> resultList.add(new SmsResult(
					s.getMsgId(), 
					s.getStatus(), 
					(StringUtils.isEmpty(s.getOrgCode()) || "0000000".equals(s.getOrgCode())) ? 0 : 1 , 
					s.getStatusDesc(), 
					s.getCreatedAt())));
			
			return this.toXml(new SmsResultResponse(list.size(), resultList));
		} else {
			return this.toXml(new Response());
		}
	}
	
	/**
	 * 验证用户是否合法
	 * @param username  用户账号
	 * @param password 密码
	 * @throws SmsApiServiceException
	 */
	private String checkUserPassword(String username, String password) throws SmsApiServiceException {
		if (StringUtils.isEmpty(username)) {
			throw new SmsApiServiceException(ErrorCode.USER_PASS_INVALID, "用户名密码错误A");
		}
		
		if (StringUtils.isEmpty(password)) {
			throw new SmsApiServiceException(ErrorCode.USER_PASS_INVALID, "用户名密码错误B");
		}
		
		try {
			String userCode = Azdg.decrypt(username);
			
			if (userCode.length() != 3) {
				throw new SmsApiServiceException(ErrorCode.USER_PASS_INVALID, "用户名密码错误C");
			}
			
			if (!this.userService.checkUserPassword(userCode, Azdg.decrypt(password))) {
				throw new SmsApiServiceException(ErrorCode.USER_PASS_INVALID, "用户名密码错误D");
			}
			return userCode;
		} catch (SmsApiServiceException e)  {
			log.error("", e);
			throw e;
		} catch (Exception e) {
			log.error("", e);
			throw new SmsApiServiceException(ErrorCode.USER_PASS_INVALID, "用户名密码错误E");
		}
	}
	
	private String toXml(Response resp) {
		return JaxbUtil.beanToXml(resp);
	}
}
